//===--- MetadataValues.h - Compiler/runtime ABI Metadata -------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This header is shared between the runtime and the compiler and
// includes target-independent information which can be usefully shared
// between them.
//
//===----------------------------------------------------------------------===//

#ifndef POLARPHP_ABI_METADATAVALUES_H
#define POLARPHP_ABI_METADATAVALUES_H

#include "polarphp/ast/Ownership.h"
#include "polarphp/basic/LLVM.h"
#include "polarphp/basic/FlagSet.h"
#include "polarphp/runtime/Unreachable.h"

#include <stdlib.h>
#include <stdint.h>

namespace polar {

enum {
   /// The number of words (pointers) in a value buffer.
      NumWords_ValueBuffer = 3,

   /// The number of words in a metadata completion context.
      NumWords_MetadataCompletionContext = 4,

   /// The number of words in a yield-once coroutine buffer.
      NumWords_YieldOnceBuffer = 4,

   /// The number of words in a yield-many coroutine buffer.
      NumWords_YieldManyBuffer = 8,
};

struct InProcess;
template <typename Runtime> struct TargetMetadata;
using Metadata = TargetMetadata<InProcess>;

/// Non-type metadata kinds have this bit set.
const unsigned MetadataKindIsNonType = 0x400;

/// Non-heap metadata kinds have this bit set.
const unsigned MetadataKindIsNonHeap = 0x200;

// The above two flags are negative because the "class" kind has to be zero,
// and class metadata is both type and heap metadata.

/// Runtime-private metadata has this bit set. The compiler must not statically
/// generate metadata objects with these kinds, and external tools should not
/// rely on the stability of these values or the precise binary layout of
/// their associated data structures.
const unsigned MetadataKindIsRuntimePrivate = 0x100;

/// Kinds of Swift metadata records.  Some of these are types, some
/// aren't.
enum class MetadataKind : uint32_t {
#define METADATAKIND(name, value) name = value,
#define ABSTRACTMETADATAKIND(name, start, end)                                 \
  name##_Start = start, name##_End = end,
#include "polarphp/abi/MetaDataKindDef.h"

   /// The largest possible non-isa-pointer metadata kind value.
   ///
   /// This is included in the enumeration to prevent against attempts to
   /// exhaustively match metadata kinds. Future Swift runtimes or compilers
   /// may introduce new metadata kinds, so for forward compatibility, the
   /// runtime must tolerate metadata with unknown kinds.
   /// This specific value is not mapped to a valid metadata kind at this time,
   /// however.
      LastEnumerated = 0x7FF,
};

const unsigned LastEnumeratedMetadataKind =
   (unsigned)MetadataKind::LastEnumerated;

inline bool isHeapMetadataKind(MetadataKind k) {
   return !((uint32_t)k & MetadataKindIsNonHeap);
}
inline bool isTypeMetadataKind(MetadataKind k) {
   return !((uint32_t)k & MetadataKindIsNonType);
}
inline bool isRuntimePrivateMetadataKind(MetadataKind k) {
   return (uint32_t)k & MetadataKindIsRuntimePrivate;
}

/// Try to translate the 'isa' value of a type/heap metadata into a value
/// of the MetadataKind enum.
inline MetadataKind getEnumeratedMetadataKind(uint64_t kind) {
   if (kind > LastEnumeratedMetadataKind)
      return MetadataKind::Class;
   return MetadataKind(kind);
}

StringRef getStringForMetadataKind(MetadataKind kind);

/// Kinds of Swift nominal type descriptor records.
enum class NominalTypeKind : uint32_t {
#define NOMINALTYPEMETADATAKIND(name, value) name = value,
#include "polarphp/abi/MetaDataKindDef.h"
};

/// The maximum supported type alignment.
const size_t MaximumAlignment = 16;

/// Flags stored in the value-witness table.
template <typename int_type>
class TargetValueWitnessFlags {
public:
   // The polarity of these bits is chosen so that, when doing struct layout, the
   // flags of the field types can be mostly bitwise-or'ed together to derive the
   // flags for the struct. (The "non-inline" and "has-extra-inhabitants" bits
   // still require additional fixup.)
   enum : uint32_t {
      AlignmentMask =       0x000000FF,
      // unused             0x0000FF00,
         IsNonPOD =            0x00010000,
      IsNonInline =         0x00020000,
      // unused             0x00040000,
         HasSpareBits =        0x00080000,
      IsNonBitwiseTakable = 0x00100000,
      HasEnumWitnesses =    0x00200000,
      Incomplete =          0x00400000,
      // unused             0xFF800000,
   };

   static constexpr const uint32_t MaxNumExtraInhabitants = 0x7FFFFFFF;

private:
   uint32_t Data;

   explicit constexpr TargetValueWitnessFlags(uint32_t data) : Data(data) {}

public:
   constexpr TargetValueWitnessFlags() : Data(0) {}

   /// The required alignment of the first byte of an object of this
   /// type, expressed as a mask of the low bits that must not be set
   /// in the pointer.
   ///
   /// This representation can be easily converted to the 'alignof'
   /// result by merely adding 1, but it is more directly useful for
   /// performing dynamic structure layouts, and it grants an
   /// additional bit of precision in a compact field without needing
   /// to switch to an exponent representation.
   ///
   /// For example, if the type needs to be 8-byte aligned, the
   /// appropriate alignment mask should be 0x7.
   size_t getAlignmentMask() const {
      return (Data & AlignmentMask);
   }
   constexpr TargetValueWitnessFlags withAlignmentMask(size_t alignMask) const {
      return TargetValueWitnessFlags((Data & ~AlignmentMask) | alignMask);
   }

   size_t getAlignment() const { return getAlignmentMask() + 1; }
   constexpr TargetValueWitnessFlags withAlignment(size_t alignment) const {
      return withAlignmentMask(alignment - 1);
   }

   /// True if the type requires out-of-line allocation of its storage.
   /// This can be the case because the value requires more storage or if it is
   /// not bitwise takable.
   bool isInlineStorage() const { return !(Data & IsNonInline); }
   constexpr TargetValueWitnessFlags withInlineStorage(bool isInline) const {
      return TargetValueWitnessFlags((Data & ~IsNonInline) |
                                     (isInline ? 0 : IsNonInline));
   }

   /// True if values of this type can be copied with memcpy and
   /// destroyed with a no-op.
   bool isPOD() const { return !(Data & IsNonPOD); }
   constexpr TargetValueWitnessFlags withPOD(bool isPOD) const {
      return TargetValueWitnessFlags((Data & ~IsNonPOD) |
                                     (isPOD ? 0 : IsNonPOD));
   }

   /// True if values of this type can be taken with memcpy. Unlike C++ 'move',
   /// 'take' is a destructive operation that invalidates the source object, so
   /// most types can be taken with a simple bitwise copy. Only types with side
   /// table references, like @weak references, or types with opaque value
   /// semantics, like imported C++ types, are not bitwise-takable.
   bool isBitwiseTakable() const { return !(Data & IsNonBitwiseTakable); }
   constexpr TargetValueWitnessFlags withBitwiseTakable(bool isBT) const {
      return TargetValueWitnessFlags((Data & ~IsNonBitwiseTakable) |
                                     (isBT ? 0 : IsNonBitwiseTakable));
   }

   /// True if this type's binary representation is that of an enum, and the
   /// enum value witness table entries are available in this type's value
   /// witness table.
   bool hasEnumWitnesses() const { return Data & HasEnumWitnesses; }
   constexpr TargetValueWitnessFlags
   withEnumWitnesses(bool hasEnumWitnesses) const {
      return TargetValueWitnessFlags((Data & ~HasEnumWitnesses) |
                                     (hasEnumWitnesses ? HasEnumWitnesses : 0));
   }

   /// True if the type with this value-witness table is incomplete,
   /// meaning that its external layout (size, etc.) is meaningless
   /// pending completion of the metadata layout.
   bool isIncomplete() const { return Data & Incomplete; }
   constexpr TargetValueWitnessFlags
   withIncomplete(bool isIncomplete) const {
      return TargetValueWitnessFlags((Data & ~Incomplete) |
                                     (isIncomplete ? Incomplete : 0));
   }

   constexpr uint32_t getOpaqueValue() const {
      return Data;
   }
};
using ValueWitnessFlags = TargetValueWitnessFlags<size_t>;

/// Flags for dynamic-cast operations.
enum class DynamicCastFlags : size_t {
   /// All flags clear.
      Default = 0x0,

   /// True if the cast is not permitted to fail.
      Unconditional = 0x1,

   /// True if the cast should 'take' the source value on success;
   /// false if the value should be copied.
      TakeOnSuccess = 0x2,

   /// True if the cast should destroy the source value on failure;
   /// false if the value should be left in place.
      DestroyOnFailure = 0x4,
};
inline bool operator&(DynamicCastFlags a, DynamicCastFlags b) {
   return (size_t(a) & size_t(b)) != 0;
}
inline DynamicCastFlags operator|(DynamicCastFlags a, DynamicCastFlags b) {
   return DynamicCastFlags(size_t(a) | size_t(b));
}
inline DynamicCastFlags operator-(DynamicCastFlags a, DynamicCastFlags b) {
   return DynamicCastFlags(size_t(a) & ~size_t(b));
}
inline DynamicCastFlags &operator|=(DynamicCastFlags &a, DynamicCastFlags b) {
   return a = (a | b);
}

/// Swift class flags.
/// These flags are valid only when isTypeMetadata().
/// When !isTypeMetadata() these flags will collide with other Swift ABIs.
enum class ClassFlags : uint32_t {
   /// Is this a Swift class from the Darwin pre-stable ABI?
   /// This bit is clear in stable ABI Swift classes.
   /// The Objective-C runtime also reads this bit.
      IsPolarphpPreStableABI = 0x1,

   /// Does this class use Swift refcounting?
      UsesSwiftRefcounting = 0x2,

   /// Has this class a custom name, specified with the @objc attribute?
      HasCustomObjCName = 0x4
};
inline bool operator&(ClassFlags a, ClassFlags b) {
   return (uint32_t(a) & uint32_t(b)) != 0;
}
inline ClassFlags operator|(ClassFlags a, ClassFlags b) {
   return ClassFlags(uint32_t(a) | uint32_t(b));
}
inline ClassFlags &operator|=(ClassFlags &a, ClassFlags b) {
   return a = (a | b);
}

/// Flags that go in a MethodDescriptor structure.
class MethodDescriptorFlags {
public:
   typedef uint32_t int_type;
   enum class Kind {
      Method,
      Init,
      Getter,
      Setter,
      ModifyCoroutine,
      ReadCoroutine,
   };

private:
   enum : int_type {
      KindMask = 0x0F,                // 16 kinds should be enough for anybody
      IsInstanceMask = 0x10,
      IsDynamicMask = 0x20,
   };

   int_type Value;

public:
   MethodDescriptorFlags(Kind kind) : Value(unsigned(kind)) {}

   MethodDescriptorFlags withIsInstance(bool isInstance) const {
      auto copy = *this;
      if (isInstance) {
         copy.Value |= IsInstanceMask;
      } else {
         copy.Value &= ~IsInstanceMask;
      }
      return copy;
   }

   MethodDescriptorFlags withIsDynamic(bool isDynamic) const {
      auto copy = *this;
      if (isDynamic)
         copy.Value |= IsDynamicMask;
      else
         copy.Value &= ~IsDynamicMask;
      return copy;
   }

   Kind getKind() const { return Kind(Value & KindMask); }

   /// Is the method marked 'dynamic'?
   bool isDynamic() const { return Value & IsDynamicMask; }

   /// Is the method an instance member?
   ///
   /// Note that 'init' is not considered an instance member.
   bool isInstance() const { return Value & IsInstanceMask; }

   int_type getIntValue() const { return Value; }
};

enum : unsigned {
   /// Number of words reserved in generic metadata patterns.
      NumGenericMetadataPrivateDataWords = 16,
};

/// Kinds of type metadata/protocol conformance records.
enum class TypeReferenceKind : unsigned {
   /// The conformance is for a nominal type referenced directly;
   /// getTypeDescriptor() points to the type context descriptor.
      DirectTypeDescriptor = 0x00,

   /// The conformance is for a nominal type referenced indirectly;
   /// getTypeDescriptor() points to the type context descriptor.
      IndirectTypeDescriptor = 0x01,

   /// The conformance is for an Objective-C class that should be looked up
   /// by class name.
      DirectObjCClassName = 0x02,

   /// The conformance is for an Objective-C class that has no nominal type
   /// descriptor.
   /// getIndirectObjCClass() points to a variable that contains the pointer to
   /// the class object, which then requires a runtime call to get metadata.
   ///
   /// On platforms without Objective-C interoperability, this case is
   /// unused.
      IndirectObjCClass = 0x03,

   // We only reserve three bits for this in the various places we store it.

   First_Kind = DirectTypeDescriptor,
   Last_Kind = IndirectObjCClass,
};

/// Flag that indicates whether an existential type is class-constrained or not.
enum class InterfaceClassConstraint : bool {
   /// The protocol is class-constrained, so only class types can conform to it.
   ///
   /// This must be 0 for ABI compatibility with Objective-C protocol_t records.
      Class = false,
   /// Any type can conform to the protocol.
      Any = true,
};

/// Identifiers for protocols with special meaning to the Swift runtime.
enum class SpecialInterface: uint8_t {
   /// Not a special protocol.
   ///
   /// This must be 0 for ABI compatibility with Objective-C protocol_t records.
      None = 0,
   /// The Error protocol.
      Error = 1,
};

/// Identifiers for protocol method dispatch strategies.
enum class InterfaceDispatchStrategy: uint8_t {
   /// Uses ObjC method dispatch.
   ///
   /// This must be 0 for ABI compatibility with Objective-C protocol_t records.
      ObjC = 0,

   /// Uses Swift protocol witness table dispatch.
   ///
   /// To invoke methods of this protocol, a pointer to a protocol witness table
   /// corresponding to the protocol conformance must be available.
      Swift = 1,
};

/// Flags for protocol descriptors.
class InterfaceDescriptorFlags {
   typedef uint32_t int_type;
   enum : int_type {
      IsPolarphp           =   1U <<  0U,
      ClassConstraint   =   1U <<  1U,

      DispatchStrategyMask  = 0xFU << 2U,
      DispatchStrategyShift = 2,

      SpecialInterfaceMask  = 0x000003C0U,
      SpecialInterfaceShift = 6,

      IsResilient       =   1U <<  10U,

      /// Reserved by the ObjC runtime.
         _ObjCReserved        = 0xFFFF0000U,
   };

   int_type Data;

   constexpr InterfaceDescriptorFlags(int_type Data) : Data(Data) {}
public:
   constexpr InterfaceDescriptorFlags() : Data(0) {}
   constexpr InterfaceDescriptorFlags withSwift(bool s) const {
      return InterfaceDescriptorFlags((Data & ~IsPolarphp) | (s ? IsPolarphp : 0));
   }
   constexpr InterfaceDescriptorFlags withClassConstraint(
      InterfaceClassConstraint c) const {
      return InterfaceDescriptorFlags((Data & ~ClassConstraint)
                                     | (bool(c) ? ClassConstraint : 0));
   }
   constexpr InterfaceDescriptorFlags withDispatchStrategy(
      InterfaceDispatchStrategy s) const {
      return InterfaceDescriptorFlags((Data & ~DispatchStrategyMask)
                                     | (int_type(s) << DispatchStrategyShift));
   }
   constexpr InterfaceDescriptorFlags
   withSpecialInterface(SpecialInterface sp) const {
      return InterfaceDescriptorFlags((Data & ~SpecialInterfaceMask)
                                     | (int_type(sp) << SpecialInterfaceShift));
   }
   constexpr InterfaceDescriptorFlags withResilient(bool s) const {
      return InterfaceDescriptorFlags((Data & ~IsResilient) | (s ? IsResilient : 0));
   }

   /// Was the protocol defined in Swift 1 or 2?
   bool isSwift() const { return Data & IsPolarphp; }

   /// Is the protocol class-constrained?
   InterfaceClassConstraint getClassConstraint() const {
      return InterfaceClassConstraint(bool(Data & ClassConstraint));
   }

   /// What dispatch strategy does this protocol use?
   InterfaceDispatchStrategy getDispatchStrategy() const {
      return InterfaceDispatchStrategy((Data & DispatchStrategyMask)
                                         >> DispatchStrategyShift);
   }

   /// Does the protocol require a witness table for method dispatch?
   bool needsWitnessTable() const {
      return needsWitnessTable(getDispatchStrategy());
   }

   static bool needsWitnessTable(InterfaceDispatchStrategy strategy) {
      switch (strategy) {
         case InterfaceDispatchStrategy::ObjC:
            return false;
         case InterfaceDispatchStrategy::Swift:
            return true;
      }

      polarphp_runtime_unreachable("Unhandled InterfaceDispatchStrategy in switch.");
   }

   /// Return the identifier if this is a special runtime-known protocol.
   SpecialInterface getSpecialInterface() const {
      return SpecialInterface(uint8_t((Data & SpecialInterfaceMask)
                                        >> SpecialInterfaceShift));
   }

   /// Can new requirements with default witnesses be added resiliently?
   bool isResilient() const { return Data & IsResilient; }

   int_type getIntValue() const {
      return Data;
   }

#ifndef NDEBUG
   LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED,
                             "Only for use in the debugger");
#endif
};

/// Flags that go in a InterfaceRequirement structure.
class InterfaceRequirementFlags {
public:
   typedef uint32_t int_type;
   enum class Kind {
      BaseInterface,
      Method,
      Init,
      Getter,
      Setter,
      ReadCoroutine,
      ModifyCoroutine,
      AssociatedTypeAccessFunction,
      AssociatedConformanceAccessFunction,
   };

private:
   enum : int_type {
      KindMask = 0x0F,                // 16 kinds should be enough for anybody
      IsInstanceMask = 0x10,
   };

   int_type Value;

public:
   InterfaceRequirementFlags(Kind kind) : Value(unsigned(kind)) {}

   InterfaceRequirementFlags withIsInstance(bool isInstance) const {
      auto copy = *this;
      if (isInstance) {
         copy.Value |= IsInstanceMask;
      } else {
         copy.Value &= ~IsInstanceMask;
      }
      return copy;
   }

   Kind getKind() const { return Kind(Value & KindMask); }

   /// Is the method an instance member?
   ///
   /// Note that 'init' is not considered an instance member.
   bool isInstance() const { return Value & IsInstanceMask; }

   int_type getIntValue() const { return Value; }

   enum : uintptr_t {
      /// Bit used to indicate that an associated type witness is a pointer to
      /// a mangled name (vs. a pointer to metadata).
         AssociatedTypeMangledNameBit = 0x01,
   };

   enum : uint8_t {
      /// Prefix byte used to identify an associated type whose mangled name
      /// is relative to the protocol's context rather than the conforming
      /// type's context.
         AssociatedTypeInInterfaceContextByte = 0xFF
   };
};

/// Flags that go in a TargetConformanceDescriptor structure.
class ConformanceFlags {
public:
   typedef uint32_t int_type;

private:
   enum : int_type {
      UnusedLowBits = 0x07,      // historical conformance kind

      TypeMetadataKindMask = 0x7 << 3, // 8 type reference kinds
      TypeMetadataKindShift = 3,

      IsRetroactiveMask = 0x01 << 6,
      IsSynthesizedNonUniqueMask = 0x01 << 7,

      NumConditionalRequirementsMask = 0xFF << 8,
      NumConditionalRequirementsShift = 8,

      HasResilientWitnessesMask = 0x01 << 16,
      HasGenericWitnessTableMask = 0x01 << 17,
   };

   int_type Value;

public:
   ConformanceFlags(int_type value = 0) : Value(value) {}

   ConformanceFlags withTypeReferenceKind(TypeReferenceKind kind) const {
      return ConformanceFlags((Value & ~TypeMetadataKindMask)
                              | (int_type(kind) << TypeMetadataKindShift));
   }

   ConformanceFlags withIsRetroactive(bool isRetroactive) const {
      return ConformanceFlags((Value & ~IsRetroactiveMask)
                              | (isRetroactive? IsRetroactiveMask : 0));
   }

   ConformanceFlags withIsSynthesizedNonUnique(
      bool isSynthesizedNonUnique) const {
      return ConformanceFlags(
         (Value & ~IsSynthesizedNonUniqueMask)
         | (isSynthesizedNonUnique ? IsSynthesizedNonUniqueMask : 0));
   }

   ConformanceFlags withNumConditionalRequirements(unsigned n) const {
      return ConformanceFlags((Value & ~NumConditionalRequirementsMask)
                              | (n << NumConditionalRequirementsShift));
   }

   ConformanceFlags withHasResilientWitnesses(bool hasResilientWitnesses) const {
      return ConformanceFlags((Value & ~HasResilientWitnessesMask)
                              | (hasResilientWitnesses? HasResilientWitnessesMask
                                                      : 0));
   }

   ConformanceFlags withHasGenericWitnessTable(
      bool hasGenericWitnessTable) const {
      return ConformanceFlags((Value & ~HasGenericWitnessTableMask)
                              | (hasGenericWitnessTable
                                 ? HasGenericWitnessTableMask
                                 : 0));
   }

   /// Retrieve the type reference kind kind.
   TypeReferenceKind getTypeReferenceKind() const {
      return TypeReferenceKind(
         (Value & TypeMetadataKindMask) >> TypeMetadataKindShift);
   }

   /// Is the conformance "retroactive"?
   ///
   /// A conformance is retroactive when it occurs in a module that is
   /// neither the module in which the protocol is defined nor the module
   /// in which the conforming type is defined. With retroactive conformance,
   /// it is possible to detect a conflict at run time.
   bool isRetroactive() const { return Value & IsRetroactiveMask; }

   /// Is the conformance synthesized in a non-unique manner?
   ///
   /// The Swift compiler will synthesize conformances on behalf of some
   /// imported entities (e.g., C typedefs with the swift_wrapper attribute).
   /// Such conformances are retroactive by nature, but the presence of multiple
   /// such conformances is not a conflict because all synthesized conformances
   /// will be equivalent.
   bool isSynthesizedNonUnique() const {
      return Value & IsSynthesizedNonUniqueMask;
   }

   /// Retrieve the # of conditional requirements.
   unsigned getNumConditionalRequirements() const {
      return (Value & NumConditionalRequirementsMask)
         >> NumConditionalRequirementsShift;
   }

   /// Whether this conformance has any resilient witnesses.
   bool hasResilientWitnesses() const {
      return Value & HasResilientWitnessesMask;
   }

   /// Whether this conformance has a generic witness table that may need to
   /// be instantiated.
   bool hasGenericWitnessTable() const {
      return Value & HasGenericWitnessTableMask;
   }

   int_type getIntValue() const { return Value; }
};

/// Flags in an existential type metadata record.
class ExistentialTypeFlags {
public:
   typedef uint32_t int_type;

private:
   enum : int_type {
      NumWitnessTablesMask  = 0x00FFFFFFU,
      ClassConstraintMask   = 0x80000000U,
      HasSuperclassMask     = 0x40000000U,
      SpecialInterfaceMask   = 0x3F000000U,
      SpecialInterfaceShift  = 24U,
   };
   int_type Data;

public:
   constexpr ExistentialTypeFlags(int_type Data) : Data(Data) {}
   constexpr ExistentialTypeFlags() : Data(0) {}
   constexpr ExistentialTypeFlags withNumWitnessTables(unsigned numTables) const {
      return ExistentialTypeFlags((Data & ~NumWitnessTablesMask) | numTables);
   }
   constexpr ExistentialTypeFlags
   withClassConstraint(InterfaceClassConstraint c) const {
      return ExistentialTypeFlags((Data & ~ClassConstraintMask)
                                  | (bool(c) ? ClassConstraintMask : 0));
   }
   constexpr ExistentialTypeFlags
   withHasSuperclass(bool hasSuperclass) const {
      return ExistentialTypeFlags((Data & ~HasSuperclassMask)
                                  | (hasSuperclass ? HasSuperclassMask : 0));
   }
   constexpr ExistentialTypeFlags
   withSpecialInterface(SpecialInterface sp) const {
      return ExistentialTypeFlags((Data & ~SpecialInterfaceMask)
                                  | (int_type(sp) << SpecialInterfaceShift));
   }

   unsigned getNumWitnessTables() const {
      return Data & NumWitnessTablesMask;
   }

   InterfaceClassConstraint getClassConstraint() const {
      return InterfaceClassConstraint(bool(Data & ClassConstraintMask));
   }

   bool hasSuperclassConstraint() const {
      return bool(Data & HasSuperclassMask);
   }

   /// Return whether this existential type represents an uncomposed special
   /// protocol.
   SpecialInterface getSpecialInterface() const {
      return SpecialInterface(uint8_t((Data & SpecialInterfaceMask)
                                        >> SpecialInterfaceShift));
   }

   int_type getIntValue() const {
      return Data;
   }
};

/// Convention values for function type metadata.
enum class FunctionMetadataConvention: uint8_t {
   Swift = 0,
   Block = 1,
   Thin = 2,
   CFunctionPointer = 3,
};

/// Flags in a function type metadata record.
template <typename int_type>
class TargetFunctionTypeFlags {
   // If we were ever to run out of space for function flags (8 bits)
   // one of the flag bits could be used to identify that the rest of
   // the flags is going to be stored somewhere else in the metadata.
   enum : int_type {
      NumParametersMask = 0x0000FFFFU,
      ConventionMask    = 0x00FF0000U,
      ConventionShift   = 16U,
      ThrowsMask        = 0x01000000U,
      ParamFlagsMask    = 0x02000000U,
      EscapingMask      = 0x04000000U,
   };
   int_type Data;

   constexpr TargetFunctionTypeFlags(int_type Data) : Data(Data) {}
public:
   constexpr TargetFunctionTypeFlags() : Data(0) {}

   constexpr TargetFunctionTypeFlags
   withNumParameters(unsigned numParams) const {
      return TargetFunctionTypeFlags((Data & ~NumParametersMask) | numParams);
   }

   constexpr TargetFunctionTypeFlags<int_type>
   withConvention(FunctionMetadataConvention c) const {
      return TargetFunctionTypeFlags((Data & ~ConventionMask)
                                     | (int_type(c) << ConventionShift));
   }

   constexpr TargetFunctionTypeFlags<int_type>
   withThrows(bool throws) const {
      return TargetFunctionTypeFlags<int_type>((Data & ~ThrowsMask) |
                                               (throws ? ThrowsMask : 0));
   }

   constexpr TargetFunctionTypeFlags<int_type>
   withParameterFlags(bool hasFlags) const {
      return TargetFunctionTypeFlags<int_type>((Data & ~ParamFlagsMask) |
                                               (hasFlags ? ParamFlagsMask : 0));
   }

   constexpr TargetFunctionTypeFlags<int_type>
   withEscaping(bool isEscaping) const {
      return TargetFunctionTypeFlags<int_type>((Data & ~EscapingMask) |
                                               (isEscaping ? EscapingMask : 0));
   }

   unsigned getNumParameters() const { return Data & NumParametersMask; }

   FunctionMetadataConvention getConvention() const {
      return FunctionMetadataConvention((Data&ConventionMask) >> ConventionShift);
   }

   bool throws() const {
      return bool(Data & ThrowsMask);
   }

   bool isEscaping() const {
      return bool (Data & EscapingMask);
   }

   bool hasParameterFlags() const { return bool(Data & ParamFlagsMask); }

   int_type getIntValue() const {
      return Data;
   }

   static TargetFunctionTypeFlags<int_type> fromIntValue(int_type Data) {
      return TargetFunctionTypeFlags(Data);
   }

   bool operator==(TargetFunctionTypeFlags<int_type> other) const {
      return Data == other.Data;
   }
   bool operator!=(TargetFunctionTypeFlags<int_type> other) const {
      return Data != other.Data;
   }
};
using FunctionTypeFlags = TargetFunctionTypeFlags<size_t>;

template <typename int_type>
class TargetParameterTypeFlags {
   enum : int_type {
      ValueOwnershipMask = 0x7F,
      VariadicMask       = 0x80,
      AutoClosureMask    = 0x100,
   };
   int_type Data;

   constexpr TargetParameterTypeFlags(int_type Data) : Data(Data) {}

public:
   constexpr TargetParameterTypeFlags() : Data(0) {}

   constexpr TargetParameterTypeFlags<int_type>
   withValueOwnership(ValueOwnership ownership) const {
      return TargetParameterTypeFlags<int_type>((Data & ~ValueOwnershipMask) |
                                                (int_type)ownership);
   }

   constexpr TargetParameterTypeFlags<int_type>
   withVariadic(bool isVariadic) const {
      return TargetParameterTypeFlags<int_type>((Data & ~VariadicMask) |
                                                (isVariadic ? VariadicMask : 0));
   }

   constexpr TargetParameterTypeFlags<int_type>
   withAutoClosure(bool isAutoClosure) const {
      return TargetParameterTypeFlags<int_type>(
         (Data & ~AutoClosureMask) | (isAutoClosure ? AutoClosureMask : 0));
   }

   bool isNone() const { return Data == 0; }
   bool isVariadic() const { return Data & VariadicMask; }
   bool isAutoClosure() const { return Data & AutoClosureMask; }

   ValueOwnership getValueOwnership() const {
      return (ValueOwnership)(Data & ValueOwnershipMask);
   }

   int_type getIntValue() const { return Data; }

   static TargetParameterTypeFlags<int_type> fromIntValue(int_type Data) {
      return TargetParameterTypeFlags(Data);
   }

   bool operator==(TargetParameterTypeFlags<int_type> other) const {
      return Data == other.Data;
   }
   bool operator!=(TargetParameterTypeFlags<int_type> other) const {
      return Data != other.Data;
   }
};
using ParameterFlags = TargetParameterTypeFlags<uint32_t>;

template <typename int_type>
class TargetTupleTypeFlags {
   enum : int_type {
      NumElementsMask = 0x0000FFFFU,
      NonConstantLabelsMask = 0x00010000U,
   };
   int_type Data;

public:
   constexpr TargetTupleTypeFlags() : Data(0) {}
   constexpr TargetTupleTypeFlags(int_type Data) : Data(Data) {}

   constexpr TargetTupleTypeFlags
   withNumElements(unsigned numElements) const {
      return TargetTupleTypeFlags((Data & ~NumElementsMask) | numElements);
   }

   constexpr TargetTupleTypeFlags<int_type> withNonConstantLabels(
      bool hasNonConstantLabels) const {
      return TargetTupleTypeFlags<int_type>(
         (Data & ~NonConstantLabelsMask) |
         (hasNonConstantLabels ? NonConstantLabelsMask : 0));
   }

   unsigned getNumElements() const { return Data & NumElementsMask; }

   bool hasNonConstantLabels() const { return Data & NonConstantLabelsMask; }

   int_type getIntValue() const { return Data; }

   static TargetTupleTypeFlags<int_type> fromIntValue(int_type Data) {
      return TargetTupleTypeFlags(Data);
   }

   bool operator==(TargetTupleTypeFlags<int_type> other) const {
      return Data == other.Data;
   }
   bool operator!=(TargetTupleTypeFlags<int_type> other) const {
      return Data != other.Data;
   }
};
using TupleTypeFlags = TargetTupleTypeFlags<size_t>;

/// Field types and flags as represented in a nominal type's field/case type
/// vector.
class FieldType {
   typedef uintptr_t int_type;
   // Type metadata is always at least pointer-aligned, so we get at least two
   // low bits to stash flags. We could use three low bits on 64-bit, and maybe
   // some high bits as well.
   enum : int_type {
      Indirect = 1,
      Weak = 2,

      TypeMask = ((uintptr_t)-1) & ~(alignof(void*) - 1),
   };
   int_type Data;

   constexpr FieldType(int_type Data) : Data(Data) {}
public:
   constexpr FieldType() : Data(0) {}
   FieldType withType(const Metadata *T) const {
      return FieldType((Data & ~TypeMask) | (uintptr_t)T);
   }

   constexpr FieldType withIndirect(bool indirect) const {
      return FieldType((Data & ~Indirect)
                       | (indirect ? Indirect : 0));
   }

   constexpr FieldType withWeak(bool weak) const {
      return FieldType((Data & ~Weak)
                       | (weak ? Weak : 0));
   }

   bool isIndirect() const {
      return bool(Data & Indirect);
   }

   bool isWeak() const {
      return bool(Data & Weak);
   }

   const Metadata *getType() const {
      return (const Metadata *)(Data & TypeMask);
   }

   int_type getIntValue() const {
      return Data;
   }
};

/// Flags for exclusivity-checking operations.
enum class ExclusivityFlags : uintptr_t {
   Read             = 0x0,
   Modify           = 0x1,
   // ActionMask can grow without breaking the ABI because the runtime controls
   // how these flags are encoded in the "value buffer". However, any additional
   // actions must be compatible with the original behavior for the old, smaller
   // ActionMask (older runtimes will continue to treat them as either a simple
   // Read or Modify).
      ActionMask       = 0x1,

   // The runtime should track this access to check against subsequent accesses.
      Tracking         = 0x20
};
static inline ExclusivityFlags operator|(ExclusivityFlags lhs,
                                         ExclusivityFlags rhs) {
   return ExclusivityFlags(uintptr_t(lhs) | uintptr_t(rhs));
}
static inline ExclusivityFlags &operator|=(ExclusivityFlags &lhs,
                                           ExclusivityFlags rhs) {
   return (lhs = (lhs | rhs));
}
static inline ExclusivityFlags getAccessAction(ExclusivityFlags flags) {
   return ExclusivityFlags(uintptr_t(flags)
                           & uintptr_t(ExclusivityFlags::ActionMask));
}
static inline bool isTracking(ExclusivityFlags flags) {
   return uintptr_t(flags) & uintptr_t(ExclusivityFlags::Tracking);
}

/// Flags for struct layout.
enum class StructLayoutFlags : uintptr_t {
   /// Reserve space for 256 layout algorithms.
      AlgorithmMask     = 0xff,

   /// The ABI baseline algorithm, i.e. the algorithm implemented in Swift 5.
      Swift5Algorithm   = 0x00,

   /// Is the value-witness table mutable in place, or does layout need to
   /// clone it?
      IsVWTMutable      = 0x100,
};
static inline StructLayoutFlags operator|(StructLayoutFlags lhs,
                                          StructLayoutFlags rhs) {
   return StructLayoutFlags(uintptr_t(lhs) | uintptr_t(rhs));
}
static inline StructLayoutFlags &operator|=(StructLayoutFlags &lhs,
                                            StructLayoutFlags rhs) {
   return (lhs = (lhs | rhs));
}
static inline StructLayoutFlags getLayoutAlgorithm(StructLayoutFlags flags) {
   return StructLayoutFlags(uintptr_t(flags)
                            & uintptr_t(StructLayoutFlags::AlgorithmMask));
}
static inline bool isValueWitnessTableMutable(StructLayoutFlags flags) {
   return uintptr_t(flags) & uintptr_t(StructLayoutFlags::IsVWTMutable);
}

/// Flags for class layout.
enum class ClassLayoutFlags : uintptr_t {
   /// Reserve space for 256 layout algorithms.
      AlgorithmMask     = 0xff,

   /// The ABI baseline algorithm, i.e. the algorithm implemented in Swift 5.
      Swift5Algorithm   = 0x00,

   /// If true, the vtable for this class and all of its superclasses was emitted
   /// statically in the class metadata. If false, the superclass vtable is
   /// copied from superclass metadata, and the immediate class vtable is
   /// initialized from the type context descriptor.
      HasStaticVTable   = 0x100,
};
static inline ClassLayoutFlags operator|(ClassLayoutFlags lhs,
                                         ClassLayoutFlags rhs) {
   return ClassLayoutFlags(uintptr_t(lhs) | uintptr_t(rhs));
}
static inline ClassLayoutFlags &operator|=(ClassLayoutFlags &lhs,
                                           ClassLayoutFlags rhs) {
   return (lhs = (lhs | rhs));
}
static inline ClassLayoutFlags getLayoutAlgorithm(ClassLayoutFlags flags) {
   return ClassLayoutFlags(uintptr_t(flags)
                           & uintptr_t(ClassLayoutFlags::AlgorithmMask));
}
static inline bool hasStaticVTable(ClassLayoutFlags flags) {
   return uintptr_t(flags) & uintptr_t(ClassLayoutFlags::HasStaticVTable);
}

/// Flags for enum layout.
enum class EnumLayoutFlags : uintptr_t {
   /// Reserve space for 256 layout algorithms.
      AlgorithmMask     = 0xff,

   /// The ABI baseline algorithm, i.e. the algorithm implemented in Swift 5.
      Swift5Algorithm   = 0x00,

   /// Is the value-witness table mutable in place, or does layout need to
   /// clone it?
      IsVWTMutable      = 0x100,
};
static inline EnumLayoutFlags operator|(EnumLayoutFlags lhs,
                                        EnumLayoutFlags rhs) {
   return EnumLayoutFlags(uintptr_t(lhs) | uintptr_t(rhs));
}
static inline EnumLayoutFlags &operator|=(EnumLayoutFlags &lhs,
                                          EnumLayoutFlags rhs) {
   return (lhs = (lhs | rhs));
}
static inline EnumLayoutFlags getLayoutAlgorithm(EnumLayoutFlags flags) {
   return EnumLayoutFlags(uintptr_t(flags)
                          & uintptr_t(EnumLayoutFlags::AlgorithmMask));
}
static inline bool isValueWitnessTableMutable(EnumLayoutFlags flags) {
   return uintptr_t(flags) & uintptr_t(EnumLayoutFlags::IsVWTMutable);
}

/// The number of arguments that will be passed directly to a generic
/// nominal type access function. The remaining arguments (if any) will be
/// passed as an array. That array has enough storage for all of the arguments,
/// but only fills in the elements not passed directly. The callee may
/// mutate the array to fill in the direct arguments.
constexpr unsigned NumDirectGenericTypeMetadataAccessFunctionArgs = 3;

/// The offset (in pointers) to the first requirement in a witness table.
constexpr unsigned WitnessTableFirstRequirementOffset = 1;

/// Kinds of context descriptor.
enum class ContextDescriptorKind : uint8_t {
   /// This context descriptor represents a module.
      Module = 0,

   /// This context descriptor represents an extension.
      Extension = 1,

   /// This context descriptor represents an anonymous possibly-generic context
   /// such as a function body.
      Anonymous = 2,

   /// This context descriptor represents a protocol context.
      Interface = 3,

   /// This context descriptor represents an opaque type alias.
      OpaqueType = 4,

   /// First kind that represents a type of any sort.
      Type_First = 16,

   /// This context descriptor represents a class.
      Class = Type_First,

   /// This context descriptor represents a struct.
      Struct = Type_First + 1,

   /// This context descriptor represents an enum.
      Enum = Type_First + 2,

   /// Last kind that represents a type of any sort.
      Type_Last = 31,
};

/// Common flags stored in the first 32-bit word of any context descriptor.
struct ContextDescriptorFlags {
private:
   uint32_t Value;

   explicit constexpr ContextDescriptorFlags(uint32_t Value)
      : Value(Value) {}
public:
   constexpr ContextDescriptorFlags() : Value(0) {}
   constexpr ContextDescriptorFlags(ContextDescriptorKind kind,
                                    bool isGeneric,
                                    bool isUnique,
                                    uint8_t version,
                                    uint16_t kindSpecificFlags)
      : ContextDescriptorFlags(ContextDescriptorFlags()
                                  .withKind(kind)
                                  .withGeneric(isGeneric)
                                  .withUnique(isUnique)
                                  .withVersion(version)
                                  .withKindSpecificFlags(kindSpecificFlags))
   {}

   /// The kind of context this descriptor describes.
   constexpr ContextDescriptorKind getKind() const {
      return ContextDescriptorKind(Value & 0x1Fu);
   }

   /// Whether the context being described is generic.
   constexpr bool isGeneric() const {
      return (Value & 0x80u) != 0;
   }

   /// Whether this is a unique record describing the referenced context.
   constexpr bool isUnique() const {
      return (Value & 0x40u) != 0;
   }

   /// The format version of the descriptor. Higher version numbers may have
   /// additional fields that aren't present in older versions.
   constexpr uint8_t getVersion() const {
      return (Value >> 8u) & 0xFFu;
   }

   /// The most significant two bytes of the flags word, which can have
   /// kind-specific meaning.
   constexpr uint16_t getKindSpecificFlags() const {
      return (Value >> 16u) & 0xFFFFu;
   }

   constexpr ContextDescriptorFlags withKind(ContextDescriptorKind kind) const {
      return assert((uint8_t(kind) & 0x1F) == uint8_t(kind)),
         ContextDescriptorFlags((Value & 0xFFFFFFE0u) | uint8_t(kind));
   }

   constexpr ContextDescriptorFlags withGeneric(bool isGeneric) const {
      return ContextDescriptorFlags((Value & 0xFFFFFF7Fu)
                                    | (isGeneric ? 0x80u : 0));
   }

   constexpr ContextDescriptorFlags withUnique(bool isUnique) const {
      return ContextDescriptorFlags((Value & 0xFFFFFFBFu)
                                    | (isUnique ? 0x40u : 0));
   }

   constexpr ContextDescriptorFlags withVersion(uint8_t version) const {
      return ContextDescriptorFlags((Value & 0xFFFF00FFu) | (version << 8u));
   }

   constexpr ContextDescriptorFlags
   withKindSpecificFlags(uint16_t flags) const {
      return ContextDescriptorFlags((Value & 0xFFFFu) | (flags << 16u));
   }

   constexpr uint32_t getIntValue() const {
      return Value;
   }
};

/// Flags for nominal type context descriptors. These values are used as the
/// kindSpecificFlags of the ContextDescriptorFlags for the type.
class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
   enum {
      // All of these values are bit offsets or widths.
      // Generic flags build upwards from 0.
      // Type-specific flags build downwards from 15.

      /// Whether there's something unusual about how the metadata is
      /// initialized.
      ///
      /// Meaningful for all type-descriptor kinds.
         MetadataInitialization = 0,
      MetadataInitialization_width = 2,

      /// Set if the type has extended import information.
      ///
      /// If true, a sequence of strings follow the null terminator in the
      /// descriptor, terminated by an empty string (i.e. by two null
      /// terminators in a row).  See TypeImportInfo for the details of
      /// these strings and the order in which they appear.
      ///
      /// Meaningful for all type-descriptor kinds.
         HasImportInfo = 2,

      // Type-specific flags:

      /// The kind of reference that this class makes to its resilient superclass
      /// descriptor.  A TypeReferenceKind.
      ///
      /// Only meaningful for class descriptors.
         Class_ResilientSuperclassReferenceKind = 9,
      Class_ResilientSuperclassReferenceKind_width = 3,

      /// Whether the immediate class members in this metadata are allocated
      /// at negative offsets.  For now, we don't use this.
         Class_AreImmediateMembersNegative = 12,

      /// Set if the context descriptor is for a class with resilient ancestry.
      ///
      /// Only meaningful for class descriptors.
         Class_HasResilientSuperclass = 13,

      /// Set if the context descriptor includes metadata for dynamically
      /// installing method overrides at metadata instantiation time.
         Class_HasOverrideTable = 14,

      /// Set if the context descriptor includes metadata for dynamically
      /// constructing a class's vtables at metadata instantiation time.
      ///
      /// Only meaningful for class descriptors.
         Class_HasVTable = 15,
   };

public:
   explicit TypeContextDescriptorFlags(uint16_t bits) : FlagSet(bits) {}
   constexpr TypeContextDescriptorFlags() {}

   enum MetadataInitializationKind {
      /// There are either no special rules for initializing the metadata
      /// or the metadata is generic.  (Genericity is set in the
      /// non-kind-specific descriptor flags.)
         NoMetadataInitialization = 0,

      /// The type requires non-trivial singleton initialization using the
      /// "in-place" code pattern.
         SingletonMetadataInitialization = 1,

      /// The type requires non-trivial singleton initialization using the
      /// "foreign" code pattern.
         ForeignMetadataInitialization = 2,

      // We only have two bits here, so if you add a third special kind,
      // include more flag bits in its out-of-line storage.
   };

   FLAGSET_DEFINE_FIELD_ACCESSORS(MetadataInitialization,
                                  MetadataInitialization_width,
                                  MetadataInitializationKind,
                                  getMetadataInitialization,
                                  setMetadataInitialization)

   bool hasSingletonMetadataInitialization() const {
      return getMetadataInitialization() == SingletonMetadataInitialization;
   }

   bool hasForeignMetadataInitialization() const {
      return getMetadataInitialization() == ForeignMetadataInitialization;
   }

   FLAGSET_DEFINE_FLAG_ACCESSORS(HasImportInfo, hasImportInfo, setHasImportInfo)

   FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasVTable,
                                 class_hasVTable,
                                 class_setHasVTable)
   FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasOverrideTable,
                                 class_hasOverrideTable,
                                 class_setHasOverrideTable)
   FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasResilientSuperclass,
                                 class_hasResilientSuperclass,
                                 class_setHasResilientSuperclass)
   FLAGSET_DEFINE_FLAG_ACCESSORS(Class_AreImmediateMembersNegative,
                                 class_areImmediateMembersNegative,
                                 class_setAreImmediateMembersNegative)

   FLAGSET_DEFINE_FIELD_ACCESSORS(Class_ResilientSuperclassReferenceKind,
                                  Class_ResilientSuperclassReferenceKind_width,
                                  TypeReferenceKind,
                                  class_getResilientSuperclassReferenceKind,
                                  class_setResilientSuperclassReferenceKind)
};

/// Extra flags for resilient classes, since we need more than 16 bits of
/// flags there.
class ExtraClassDescriptorFlags : public FlagSet<uint32_t> {
   enum {
      /// Set if the context descriptor includes a pointer to an Objective-C
      /// resilient class stub structure. See the description of
      /// TargetObjCResilientClassStubInfo in Metadata.h for details.
      ///
      /// Only meaningful for class descriptors when Objective-C interop is
      /// enabled.
         HasObjCResilientClassStub = 0,
   };

public:
   explicit ExtraClassDescriptorFlags(uint32_t bits) : FlagSet(bits) {}
   constexpr ExtraClassDescriptorFlags() {}

   FLAGSET_DEFINE_FLAG_ACCESSORS(HasObjCResilientClassStub,
                                 hasObjCResilientClassStub,
                                 setObjCResilientClassStub)
};

/// Flags for protocol context descriptors. These values are used as the
/// kindSpecificFlags of the ContextDescriptorFlags for the protocol.
class InterfaceContextDescriptorFlags : public FlagSet<uint16_t> {
   enum {
      /// Whether this protocol is class-constrained.
         HasClassConstraint = 0,
      HasClassConstraint_width = 1,

      /// Whether this protocol is resilient.
         IsResilient = 1,

      /// Special protocol value.
         SpecialInterfaceKind = 2,
      SpecialInterfaceKind_width = 6,
   };

public:
   explicit InterfaceContextDescriptorFlags(uint16_t bits) : FlagSet(bits) {}
   constexpr InterfaceContextDescriptorFlags() {}

   FLAGSET_DEFINE_FLAG_ACCESSORS(IsResilient, isResilient, setIsResilient)

   FLAGSET_DEFINE_FIELD_ACCESSORS(HasClassConstraint,
                                  HasClassConstraint_width,
                                  InterfaceClassConstraint,
                                  getClassConstraint,
                                  setClassConstraint)

   FLAGSET_DEFINE_FIELD_ACCESSORS(SpecialInterfaceKind,
                                  SpecialInterfaceKind_width,
                                  SpecialInterface,
                                  getSpecialInterface,
                                  setSpecialInterface)
};

/// Flags for anonymous type context descriptors. These values are used as the
/// kindSpecificFlags of the ContextDescriptorFlags for the anonymous context.
class AnonymousContextDescriptorFlags : public FlagSet<uint16_t> {
   enum {
      /// Whether this anonymous context descriptor is followed by its
      /// mangled name, which can be used to match the descriptor at runtime.
         HasMangledName = 0,
   };

public:
   explicit AnonymousContextDescriptorFlags(uint16_t bits) : FlagSet(bits) {}
   constexpr AnonymousContextDescriptorFlags() {}

   FLAGSET_DEFINE_FLAG_ACCESSORS(HasMangledName, hasMangledName,
                                 setHasMangledName)
};

enum class GenericParamKind : uint8_t {
   /// A type parameter.
      Type = 0,

   Max = 0x3F,
};

class GenericParamDescriptor {
   uint8_t Value;

   explicit constexpr GenericParamDescriptor(uint8_t Value)
      : Value(Value) {}
public:
   constexpr GenericParamDescriptor(GenericParamKind kind,
                                    bool hasKeyArgument,
                                    bool hasExtraArgument)
      : GenericParamDescriptor(GenericParamDescriptor(0)
                                  .withKind(kind)
                                  .withKeyArgument(hasKeyArgument)
                                  .withExtraArgument(hasExtraArgument))
   {}

   constexpr bool hasKeyArgument() const {
      return (Value & 0x80u) != 0;
   }

   constexpr bool hasExtraArgument() const {
      return (Value & 0x40u) != 0;
   }

   constexpr GenericParamKind getKind() const {
      return GenericParamKind(Value & 0x3Fu);
   }

   constexpr GenericParamDescriptor
   withKeyArgument(bool hasKeyArgument) const {
      return GenericParamDescriptor((Value & 0x7Fu)
                                    | (hasKeyArgument ? 0x80u : 0));
   }

   constexpr GenericParamDescriptor
   withExtraArgument(bool hasExtraArgument) const {
      return GenericParamDescriptor((Value & 0xBFu)
                                    | (hasExtraArgument ? 0x40u : 0));
   }

   constexpr GenericParamDescriptor withKind(GenericParamKind kind) const {
      return assert((uint8_t(kind) & 0x3Fu) == uint8_t(kind)),
         GenericParamDescriptor((Value & 0xC0u) | uint8_t(kind));
   }

   constexpr uint8_t getIntValue() const {
      return Value;
   }
};

enum class GenericRequirementKind : uint8_t {
   /// A protocol requirement.
      Interface = 0,
   /// A same-type requirement.
      SameType = 1,
   /// A base class requirement.
      BaseClass = 2,
   /// A "same-conformance" requirement, implied by a same-type or base-class
   /// constraint that binds a parameter with protocol requirements.
      SameConformance = 3,
   /// A layout constraint.
      Layout = 0x1F,
};

class GenericRequirementFlags {
   uint32_t Value;

   explicit constexpr GenericRequirementFlags(uint32_t Value)
      : Value(Value) {}
public:
   constexpr GenericRequirementFlags(GenericRequirementKind kind,
                                     bool hasKeyArgument,
                                     bool hasExtraArgument)
      : GenericRequirementFlags(GenericRequirementFlags(0)
                                   .withKind(kind)
                                   .withKeyArgument(hasKeyArgument)
                                   .withExtraArgument(hasExtraArgument))
   {}

   constexpr bool hasKeyArgument() const {
      return (Value & 0x80u) != 0;
   }

   constexpr bool hasExtraArgument() const {
      return (Value & 0x40u) != 0;
   }

   constexpr GenericRequirementKind getKind() const {
      return GenericRequirementKind(Value & 0x1Fu);
   }

   constexpr GenericRequirementFlags
   withKeyArgument(bool hasKeyArgument) const {
      return GenericRequirementFlags((Value & 0x7Fu)
                                     | (hasKeyArgument ? 0x80u : 0));
   }

   constexpr GenericRequirementFlags
   withExtraArgument(bool hasExtraArgument) const {
      return GenericRequirementFlags((Value & 0xBFu)
                                     | (hasExtraArgument ? 0x40u : 0));
   }

   constexpr GenericRequirementFlags
   withKind(GenericRequirementKind kind) const {
      return assert((uint8_t(kind) & 0x1Fu) == uint8_t(kind)),
         GenericRequirementFlags((Value & 0xE0u) | uint8_t(kind));
   }

   constexpr uint32_t getIntValue() const {
      return Value;
   }
};

enum class GenericRequirementLayoutKind : uint32_t {
   // A class constraint.
      Class = 0,
};

class GenericEnvironmentFlags {
   uint32_t Value;

   enum : uint32_t {
      NumGenericParameterLevelsMask = 0xFFF,
      NumGenericRequirementsShift = 12,
      NumGenericRequirementsMask = 0xFFFF << NumGenericRequirementsShift,
   };

   constexpr explicit GenericEnvironmentFlags(uint32_t value) : Value(value) { }

public:
   constexpr GenericEnvironmentFlags() : Value(0) { }

   constexpr GenericEnvironmentFlags
   withNumGenericParameterLevels(uint16_t numGenericParameterLevels) const {
      return GenericEnvironmentFlags((Value &~ NumGenericParameterLevelsMask)
                                     | numGenericParameterLevels);
   }

   constexpr GenericEnvironmentFlags
   withNumGenericRequirements(uint16_t numGenericRequirements) const {
      return GenericEnvironmentFlags((Value &~ NumGenericRequirementsMask)
                                     | (numGenericRequirements << NumGenericRequirementsShift));
   }

   constexpr unsigned getNumGenericParameterLevels() const {
      return Value & NumGenericParameterLevelsMask;
   }

   constexpr unsigned getNumGenericRequirements() const {
      return (Value & NumGenericRequirementsMask) >> NumGenericRequirementsShift;
   }

   constexpr uint32_t getIntValue() const {
      return Value;
   }
};

/// Flags used by generic metadata patterns.
class GenericMetadataPatternFlags : public FlagSet<uint32_t> {
   enum {
      // All of these values are bit offsets or widths.
      // General flags build up from 0.
      // Kind-specific flags build down from 31.

      /// Does this pattern have an extra-data pattern?
         HasExtraDataPattern = 0,

      // Class-specific flags.

      /// Does this pattern have an immediate-members pattern?
         Class_HasImmediateMembersPattern = 31,

      // Value-specific flags.

      /// For value metadata: the metadata kind of the type.
         Value_MetadataKind = 21,
      Value_MetadataKind_width = 11,
   };

public:
   explicit GenericMetadataPatternFlags(uint32_t bits) : FlagSet(bits) {}
   constexpr GenericMetadataPatternFlags() {}

   FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasImmediateMembersPattern,
                                 class_hasImmediateMembersPattern,
                                 class_setHasImmediateMembersPattern)

   FLAGSET_DEFINE_FLAG_ACCESSORS(HasExtraDataPattern,
                                 hasExtraDataPattern,
                                 setHasExtraDataPattern)

   FLAGSET_DEFINE_FIELD_ACCESSORS(Value_MetadataKind,
                                  Value_MetadataKind_width,
                                  MetadataKind,
                                  value_getMetadataKind,
                                  value_setMetadataKind)
};

/// The public state of a metadata.
enum class MetadataState : size_t {
   // The values of this enum are set up to give us some future flexibility
   // in adding states.  The compiler emits unsigned comparisons against
   // these values, so adding states that aren't totally ordered with at
   // least the existing values will pose a problem; but we also use a
   // gradually-shrinking bitset in case it's useful to track states as
   // separate capabilities.  Specific values have been chosen so that a
   // MetadataRequest of 0 represents a blocking complete request, which
   // is the most likely request from ordinary code.  The total size of a
   // state is kept to 8 bits so that a full request, even with additional
   // flags, can be materialized as a single immediate on common ISAs, and
   // so that the state can be extracted with a byte truncation.
   // The spacing between states reflects guesswork about where new
   // states/capabilities are most likely to be added.

   /// The metadata is fully complete.  By definition, this is the
   /// end-state of all metadata.  Generally, metadata is expected to be
   /// complete before it can be passed to arbitrary code, e.g. as
   /// a generic argument to a function or as a metatype value.
   ///
   /// In addition to the requirements of NonTransitiveComplete, certain
   /// transitive completeness guarantees must hold.  Most importantly,
   /// complete nominal type metadata transitively guarantee the completion
   /// of their stored generic type arguments and superclass metadata.
      Complete = 0x00,

   /// The metadata is fully complete except for any transitive completeness
   /// guarantees.
   ///
   /// In addition to the requirements of LayoutComplete, metadata in this
   /// state must be prepared for all basic type operations.  This includes:
   ///
   ///   - any sort of internal layout necessary to allocate and work
   ///     with concrete values of the type, such as the instance layout
   ///     of a class;
   ///
   ///   - any sort of external dynamic registration that might be required
   ///     for the type, such as the realization of a class by the Objective-C
   ///     runtime; and
   ///
   ///   - the initialization of any other information kept in the metadata
   ///     object, such as a class's v-table.
      NonTransitiveComplete = 0x01,

   /// The metadata is ready for the layout of other types that store values
   /// of this type.
   ///
   /// In addition to the requirements of Abstract, metadata in this state
   /// must have a valid value witness table, meaning that its size,
   /// alignment, and basic type properties (such as POD-ness) have been
   /// computed.
      LayoutComplete = 0x3F,

   /// The metadata has its basic identity established.  It is possible to
   /// determine what formal type it corresponds to.  Among other things, it
   /// is possible to use the runtime mangling facilities with the type.
   ///
   /// For example, a metadata for a generic struct has a metadata kind,
   /// a type descriptor, and all of its type arguments.  However, it does not
   /// necessarily have a meaningful value-witness table.
   ///
   /// References to other types that are not part of the type's basic identity
   /// may not yet have been established.  Most crucially, this includes the
   /// superclass pointer.
      Abstract = 0xFF,
};

/// Something that can be static_asserted in all the places where we do
/// comparisons on metadata states.
constexpr const bool MetadataStateIsReverseOrdered = true;

/// Return true if the first metadata state is at least as advanced as the
/// second.
inline bool isAtLeast(MetadataState lhs, MetadataState rhs) {
   static_assert(MetadataStateIsReverseOrdered,
                 "relying on the ordering of MetadataState here");
   return size_t(lhs) <= size_t(rhs);
}

/// Kinds of requests for metadata.
class MetadataRequest : public FlagSet<size_t> {
   using IntType = size_t;
   using super = FlagSet<IntType>;

public:
   enum : IntType {
      State_bit = 0,
      State_width = 8,

      /// A blocking request will not return until the runtime is able to produce
      /// metadata with the given kind.  A non-blocking request will return
      /// "immediately", producing an abstract metadata and a flag saying that
      /// the operation failed.
      ///
      /// An abstract request will never be non-zero.
         NonBlocking_bit = 8,
   };

   MetadataRequest(MetadataState state, bool isNonBlocking = false) {
      setState(state);
      setIsNonBlocking(isNonBlocking);
   }
   explicit MetadataRequest(IntType bits) : super(bits) {}
   constexpr MetadataRequest() {}

   FLAGSET_DEFINE_EQUALITY(MetadataRequest)

   FLAGSET_DEFINE_FIELD_ACCESSORS(State_bit,
                                  State_width,
                                  MetadataState,
                                  getState,
                                  setState)

   FLAGSET_DEFINE_FLAG_ACCESSORS(NonBlocking_bit,
                                 isNonBlocking,
                                 setIsNonBlocking)
   bool isBlocking() const { return !isNonBlocking(); }

   /// Is this request satisfied by a metadata that's in the given state?
   bool isSatisfiedBy(MetadataState state) const {
      return isAtLeast(state, getState());
   }
};

/// Flags for Builtin.IntegerLiteral values.
class IntegerLiteralFlags {
public:
   enum : size_t {
      IsNegativeFlag = 0x1,

      // Save some space for other flags.

      BitWidthShift = 8,
   };

private:
   size_t Data;

   explicit IntegerLiteralFlags(size_t data) : Data(data) {}

public:
   constexpr IntegerLiteralFlags(size_t bitWidth, bool isNegative)
      : Data((bitWidth << BitWidthShift)
             | (isNegative ? IsNegativeFlag : 0)) {}

   /// Return true if the value is negative.
   bool isNegative() const { return Data & IsNegativeFlag; }

   /// Return the minimum number of bits necessary to store the value in
   /// two's complement, including a leading sign bit.
   unsigned getBitWidth() const { return Data >> BitWidthShift; }

   size_t getOpaqueValue() const { return Data; }
   static IntegerLiteralFlags getFromOpaqueValue(size_t value) {
      return IntegerLiteralFlags(value);
   }
};

} // end namespace polar

#endif // POLARPHP_ABI_METADATAVALUES_H
